iT邦幫忙

2026 iThome 鐵人賽

DAY 23
0
IT Operation

從裸機到叢集:以 Proxmox VE、Ceph、OPNsense 與 PostgreSQL HA 建立可驗證的安全私有雲系列 第 23

Day 23|PostgreSQL HA 叢集實作(上):使用 Patroni 完成自動選主與狀態管理

  • 分享至 

  • xImage
  •  

前一天建立的 etcd 已經能用多數決保存一致的協調狀態。今天要加入 Patroni,由它持續檢查 PostgreSQL、執行資料庫角色變更,並把 PostgreSQL 原生串流複寫與 etcd 的領導者鎖定連接起來。

本文先從 PostgreSQL 程序、資料路徑與控制路徑開始,再依序說明 Patroni 設定、首次建立、複本加入、控制迴圈與 REST API。最後才建立三節點高可用性(High Availability,HA)叢集,確認只有一台主節點(Primary)、兩台複本(Replica),而且 PostgreSQL 的生命週期已交由 Patroni 管理。


今天要解決的問題

  1. Patroni 是什麼,分散式設定儲存(Distributed Configuration Store,DCS)在 Patroni、PostgreSQL 與 etcd 之間扮演什麼角色?
  2. 為什麼導入 Patroni 後,PostgreSQL 程序要由它統一管理?
  3. 本機設定、首次建立設定與動態設定如何分工?
  4. 第一台節點如何建立叢集,後續節點又如何成為 Replica?
  5. Patroni 控制迴圈如何維持領導者鎖定與資料庫角色?
  6. REST API 如何對外表達目前的角色與健康狀態?

本文閱讀方式

  • 完整理解技術與底層原理:依序閱讀全文。
  • 掌握完成部署所需的基本概念:優先閱讀標有「⭐」的章節。
  • 快速了解當天的部署內容:閱讀文末的 Lab/實作章節。
  • 跟著系列建立完整系統:依照 GitHub 詳細部署文件 的天數順序操作。

串流複寫完成後,為什麼還需要 Patroni?

看到這裡,你可能會疑惑:前幾天不是已經完成多個 PostgreSQL 執行個體的串流複寫,為什麼今天還要建立叢集?先釐清叢集在這裡的意思。PostgreSQL 官方所稱的資料庫叢集(Database Cluster),是由單一 PostgreSQL 伺服器執行個體管理的一組資料庫與資料目錄。本系列所說的 PostgreSQL HA 叢集,則是多個 PostgreSQL 執行個體共同維持一個可用資料庫服務的架構。

前面建立的手動串流複寫已經能把 Primary 的 WAL 傳到 Replica,解決資料副本同步。角色判斷、故障後由哪台接手、舊 Primary 如何安全回歸,以及各節點的生命週期需要人工處理。Patroni 接著補上這層控制能力,透過 etcd 協調單一 Primary,並由各節點上的控制迴圈持續管理角色與 PostgreSQL 程序。

⭐ Patroni 連接資料庫與一致決策

Patroni 標誌

圖(一)Patroni 是本系列用來協調 PostgreSQL 角色與生命週期的高可用性框架。

Patroni 是以 Python 開發的開源 PostgreSQL 高可用性框架。它在每台資料庫節點上執行,檢查本機 PostgreSQL 狀態,透過 DCS 協調角色,並在必要時管理 PostgreSQL 的啟動、停止、提升、降級與複本初始化。資料由 PostgreSQL 保存並透過原生串流複寫傳送。

DCS 是 Patroni 對協調狀態儲存層的統稱,提供所有 Patroni 節點共同讀寫一致叢集狀態的位置。本系列由 etcd 擔任 DCS,保存成員狀態、共用設定、初始化標記與具有期限的領導者 Key。Patroni 讀取這些資料後,判斷哪個節點可以維持 Primary、哪些節點應保持 Replica。簡單來說,DCS 是 Patroni 使用的協調儲存層,etcd 是實際提供這項能力的服務。

前面兩天完成的元件分工可以整理如下:

元件 主要責任 不負責的工作
PostgreSQL 處理 SQL、保存資料並透過 WAL 執行串流複寫 跨節點安全選出唯一可寫角色
etcd(本系列的 DCS) 以 Raft、多數決與租約保存少量一致狀態 分析 WAL、啟停 PostgreSQL 或傳送資料
Patroni 檢查 PostgreSQL 與 DCS 狀態,管理程序、角色及複寫設定 儲存資料表、轉送 SQL 或取代 WAL 複寫

應用程式連線直接進入 PostgreSQL 的 TCP 5432,WAL 也由 PostgreSQL 傳給 Replica。Patroni 與 etcd 位於控制路徑,SQL 則沿著資料路徑傳送:

SQL、WAL、Patroni REST API 與 etcd 控制狀態分屬資料路徑與控制路徑

圖(二)SQL 與 WAL 位於資料路徑,Patroni、etcd 與 REST API 則組成資料庫角色的控制路徑。

這個分層有兩個重要結果。第一,Patroni 或 etcd 短暫無法回應時,既有 SQL 連線可能繼續使用。若目前 Primary 無法持續確認自己的領導者鎖定,Patroni 便會採取保守動作,避免兩台資料庫同時接受寫入。第二,Patroni 選出資料庫角色後,還需要另一層固定入口把新的應用程式連線送往正確節點。今天先完成角色控制,固定連線入口留待後續建立。

⭐ 一個 PostgreSQL 執行個體只保留一個控制來源

未導入 Patroni 時,Debian 可以透過 postgresql.service、版本化的 systemd 服務單元(Unit)或 pg_ctlcluster 管理 PostgreSQL。導入 Patroni 後,同一個資料目錄的啟停、角色與復原設定必須改由 Patroni 統一控制。

如果作業系統服務和 Patroni 同時管理同一個 PostgreSQL 執行個體,可能出現兩邊反覆啟停程序、重複占用 TCP 5432,或舊節點在錯誤時機重新接受寫入。正確關係是由 systemd 維持 Patroni 程序,再由 Patroni 啟動並監督 PostgreSQL:

systemd 啟動並監督 Patroni,再由 Patroni 管理 PostgreSQL

圖(三)作業系統管理 Patroni,Patroni 再成為 PostgreSQL 執行個體唯一的生命週期管理者。

操作入口必須符合責任邊界:查詢資料庫狀態使用 SQL。檢查叢集、重新載入設定與維護角色則使用 patronictl 或受保護的 REST API。特殊修復若需要暫時手動控制 PostgreSQL,應先讓 Patroni 進入維護模式並依維運手冊(Runbook)操作,確保同一時間只有一套控制來源生效。

⭐ 三種不同的設定

Patroni 設定由本機設定、動態設定,以及只在第一次建立叢集時使用的 Bootstrap 區塊共同組成,三台主機的 YAML 也會包含各自的節點名稱、位址與憑證路徑。

設定類型 保存位置 適合保存的內容 變更方式
本機設定(Local Configuration) 每台節點的 Patroni YAML 或環境變數 name、監聽位址、連線位址、資料目錄、憑證路徑與本機標籤 修改該節點設定後重新載入 Patroni
動態設定(Dynamic Configuration) DCS ttlloop_waitretry_timeout、候選延遲門檻及需要整個叢集一致的 PostgreSQL 參數 使用 patronictl edit-config 或 REST API 修改
首次建立設定(Bootstrap Configuration) 最初寫在 YAML,建立時轉成 DCS 初始設定 initdb、初始 pg_hba、初始動態設定與建立後動作 只在叢集第一次建立時使用

最小設定檔如何對應三種設定

以下骨架只保留辨識設定層級所需的欄位。scopenamespace、etcd 端點與 Bootstrap 內容由三台共用。name、REST 位址、PostgreSQL 位址與資料目錄則依節點調整。可直接部署的 TLS、驗證規則與帳密設定留在實作文件。

scope: iron-pg
namespace: /service/
name: pg01

restapi:
  listen: 10.77.30.11:8008
  connect_address: 10.77.30.11:8008

etcd3:
  hosts: 10.77.30.11:2379,10.77.30.12:2379,10.77.30.13:2379
  protocol: https
  cacert: /etc/patroni/etcd-tls/ca.crt
  cert: /etc/patroni/etcd-tls/node.crt
  key: /etc/patroni/etcd-tls/node.key

bootstrap:
  dcs:
    ttl: 30
    loop_wait: 10
    retry_timeout: 10
    maximum_lag_on_failover: 1048576
    postgresql:
      use_pg_rewind: true
      use_slots: true

postgresql:
  listen: 10.77.30.11:5432
  connect_address: 10.77.30.11:5432
  data_dir: /var/lib/postgresql/18/patroni
  bin_dir: /usr/lib/postgresql/18/bin

一般 Patroni 設定中,環境變數可以覆蓋本機設定,本機設定又能覆蓋多數動態值。但部分維持 PostgreSQL 叢集一致性所需的參數只能由動態設定管理,另有少數安全值會由 Patroni 直接強制設定。因此修改後要以 Patroni 顯示的有效設定與 pending restart 狀態判斷實際結果。

scopenamespacename 組成叢集身分

三個欄位看起來相似,實際上分別回答叢集、DCS 路徑與節點身分:

欄位 本次值 意義
scope iron-pg 三台 Patroni 共同加入的 PostgreSQL 叢集名稱
namespace /service/ Patroni 在 DCS 使用的路徑前綴
name pg01pg02pg03 每個 Patroni 成員的唯一名稱

相同 namespacescope 讓三台節點讀寫同一組 DCS 狀態,不同 name 則讓每台能發布自己的 REST 位址、PostgreSQL 位址、角色與複寫進度。若不同環境誤用相同路徑,可能互相看見不屬於自己的成員。若三台 scope 不同,則會被視為三套互不相關的叢集。

Patroni 在 etcd 實際讀寫哪些資料

以本次 namespace: /service/scope: iron-pg 為例,Patroni 會在 /service/iron-pg/ 下交換少量控制資料。實際 Key 會隨 Patroni 版本與啟用功能略有增減,核心內容如下:

etcd 路徑 保存內容 更新時機
/service/iron-pg/initialize PostgreSQL 叢集的初始化標記與系統識別 某台節點取得初始化權時以原子操作建立
/service/iron-pg/config ttlloop_wait、複寫參數等動態設定 首次建立及管理者修改共用設定時
/service/iron-pg/leader 目前持有資料庫領導者鎖定的 Patroni 成員名稱 取得鎖定後建立,Primary 持續更新有效期限
/service/iron-pg/members/pg01 各節點的 PostgreSQL/REST 位址、角色、狀態、時間軸與標籤等成員資料 每台 Patroni 在控制迴圈中更新
/service/iron-pg/status 最近的 Primary WAL 位置與永久複寫槽狀態 目前領導者在狀態改變時更新
/service/iron-pg/history PostgreSQL 時間軸與角色切換歷史 發生角色切換後更新

執行計畫性切換或故障切換時可能出現 /failover Key。啟用同步複寫時,/sync Key 則保存目前 Primary 與同步複本狀態。etcd 保存的內容限於協調狀態。SQL 查詢、資料表內容、完整 WAL、資料庫密碼與 TLS 私鑰保存在各自的資料庫或檔案路徑。這些控制資料讓每台 Patroni 對叢集身分、目前角色與候選條件取得一致看法。

⭐ 首次建立與複本加入使用不同流程

第一次啟動時,DCS 尚未存在這個 scope 的初始化狀態。三台 Patroni 可以接近同時啟動並各自嘗試建立 initialize Key,但 etcd 的原子操作只會讓其中一台成功。取得初始化權的節點依照 Bootstrap 設定執行 initdb 或自訂建立方法,準備 PostgreSQL、初始角色、驗證規則與動態設定,再成為第一個 Primary。此處的初始化權只負責協調一次性的叢集建立。叢集運作期間則由可續期的領導者 Key 決定哪一台 PostgreSQL 維持 Primary。

其他節點看見 DCS 已完成初始化後,會加入既有叢集。它們會尋找可以複製的來源,預設使用 PostgreSQL 的 pg_basebackup 建立一致的資料目錄,再接續 WAL 成為 Replica:

三台 Patroni 競爭初始化權,勝出節點建立 Primary,其餘節點再從 Primary 建立複本

圖(四)三台 Patroni 都會嘗試建立 initialize Key,etcd 只讓其中一台取得初始化權並執行 Bootstrap。其餘兩台讀取已建立的叢集狀態後,主動連向 Primary 執行 pg_basebackup,從 Primary 取得基礎備份並持續接收 WAL,最後形成一台 Primary 與兩台 Replica。

bootstrap.dcsbootstrap.pg_hba 只在首次建立時生效。叢集建立後,共用設定改由 patronictl edit-config 或 REST API 管理。本機名稱、位址與憑證路徑等節點差異則繼續留在各自主機的 YAML。

本次先保存舊資料目錄與邏輯備份(Dump),再由 Patroni 建立新的乾淨叢集。等一台 Primary 與兩台 Replica 成形後,只對目前 Primary 還原 Dump,資料再經由 PostgreSQL 串流複寫到兩台 Replica。pg_basebackup 在這裡負責建立新複本的共同起點。獨立備份與災難復原需要另外規劃。

控制迴圈持續校正期望角色與實際狀態

每台資料庫節點上的 Patroni 都會執行高可用性控制迴圈(HA Loop)。每輪會讀取 DCS、查詢本機 PostgreSQL、發布成員資訊,然後根據領導者鎖定、資料庫角色、複寫位置與節點標籤決定下一個動作。

Patroni 每輪高可用性控制迴圈的判斷流程

圖(五)每台 Patroni 反覆比對 DCS 與本機 PostgreSQL 狀態,再維持或修正目前角色。

etcd 的 Raft 領導者(Leader)、Patroni 領導者鎖定持有者與 PostgreSQL Primary 是三個不同概念。Raft Leader 負責協調 etcd 日誌。各 Patroni 程序則競爭 DCS 中的資料庫領導者 Key。成功持有並持續更新該 Key 的 Patroni,才有資格讓自己的 PostgreSQL 維持 Primary。PostgreSQL 狀態比較與 promote 動作由 Patroni 負責,etcd 專注保存一致的協調狀態。

三個時間參數共同形成判斷節奏

參數 本次值 作用
loop_wait 10 秒 一輪正常控制迴圈結束後的等待時間
retry_timeout 10 秒 Patroni 對 DCS 或 PostgreSQL 操作重試使用的時間界線
ttl 30 秒 領導者鎖定的有效期限

Patroni 要求這些參數符合:

loop_wait + 2 × retry_timeout ≤ ttl

本次設定:10 + 2 × 10 = 30 秒

ttl 代表領導鎖的租約期限,復原時間目標(Recovery Time Objective,RTO)則要從明確的故障起點量測到服務恢復。實際中斷還會包含故障發生在控制迴圈中的位置、DCS 重試、候選節點判斷、PostgreSQL 提升,以及用戶端重新建立連線所需的時間。今天先確認控制迴圈與參數關係。角色切換與服務恢復時間要在具備明確起點、終點與用戶端探測後量測。

maximum_lag_on_failover 則限制落後超過指定 WAL 位元組數的 Replica 參與自動接手。本次設為 1048576,也就是 1 MiB。這項數值只定義候選資格門檻。實際資料遺失範圍需透過故障測試量測,並與事先定義的復原點目標(Recovery Point Objective,RPO)比較。

⭐ REST API 將角色轉成可判讀的狀態

每台 Patroni 預設透過 REST API 對外提供本機狀態。它一方面供 Patroni 成員與 patronictl 查詢或管理叢集,另一方面也能讓代理服務與監控系統用 HTTP 狀態碼判斷節點是否符合特定角色。

REST 端點 HTTP 200 代表的狀態 適合用途
/primary/read-write PostgreSQL 正常,而且本機是持有領導者鎖定的 Primary 尋找可寫節點
/replica PostgreSQL 正常、本機是 Replica,且未設定 noloadbalance 尋找可讀複本
/replica?lag=1MB 除了符合 Replica 條件,複寫落後也在門檻內 排除過度落後的唯讀節點
/health 本機 PostgreSQL 正在執行 單純檢查程序健康,不判斷角色
/patroni 回傳本機 Patroni 與 PostgreSQL 的詳細狀態 維運與監控判讀

同一個節點的 /health/primary 可能分別回傳 200 與 503:前者只說 PostgreSQL 正常,後者還要求它是持有鎖定的 Primary。這也是健康、角色與能否接受特定流量必須分開檢查的原因。

REST 健康檢查只回報 Patroni 已經決定的角色,代理服務再依結果選擇新連線要送往哪個後端節點。具有切換、重新啟動、重新初始化與修改設定能力的 REST 方法則屬於管理介面,TCP 8008 僅開放給 Patroni 節點、受控管理、監控及必要的代理來源。

常用命令如何交叉確認叢集

以下命令涵蓋設定驗證、角色、動態設定、資料庫實際狀態、REST 端點與服務紀錄,適合在日常檢查時依序使用:

# 驗證本機 Patroni YAML
sudo -u postgres patroni --validate-config /etc/patroni/config.yml

# 查看三台成員與目前角色
sudo -u postgres patronictl -c /etc/patroni/config.yml list

# 查看 DCS 內的共用動態設定
sudo -u postgres patronictl -c /etc/patroni/config.yml show-config iron-pg

# 由 PostgreSQL 自身確認本機是否處於復原狀態
sudo -u postgres psql -d postgres -Atc 'SELECT pg_is_in_recovery();'

# 在目前 Primary 查看兩台 Replica 的串流狀態
sudo -u postgres psql -d postgres -P pager=off \
  -c "SELECT application_name,client_addr,state,sync_state FROM pg_stat_replication ORDER BY application_name;"

# 比較三台節點的 Primary 端點,正常情況只有一台回傳 HTTP 200
for host in 10.77.30.11 10.77.30.12 10.77.30.13; do
  printf '%s ' "$host"
  curl -sS -o /dev/null -w 'HTTP %{http_code}\n' \
    "http://${host}:8008/primary"
done

# 查看 Patroni 最近的服務紀錄
sudo journalctl -u patroni -n 100 --no-pager

建立完成後如何判斷叢集狀態

三個 Patroni 程序正在執行只能確認程序存活。PostgreSQL HA 叢集成立還要交叉確認以下狀態:

要確認的關係 觀察方式 正常結果
Patroni 成員與角色 patronictl list 三個成員、單一 Leader 與兩個 Replica
PostgreSQL 實際角色 pg_is_in_recovery() Primary 為 false,Replica 為 true
PostgreSQL 複寫連線 pg_stat_replication Primary 看見兩條 streaming 連線
REST 角色端點 /primary/replica 只有符合該角色的節點回傳 200
共用動態設定 patronictl show-config 三台共用相同 DCS 設定
程序管理關係 systemd 與程序資訊 Patroni 啟用,套件預設 PostgreSQL 服務不再自動管理本次執行個體

今天的完成條件是建立並讀懂這個穩定狀態。叢集基線確認正確後,計畫性切換、非計畫性故障、時間軸改變、pg_rewind 與舊 Primary 回歸再以獨立測試驗證,讓初始設定與故障處置的結果可以分開判讀。


本次 Lab:建立 Patroni 叢集並驗證控制關係

本次先保存原有的手動串流複寫資料,再建立新的 Patroni 資料目錄。實作會先單獨啟動 pg01,讓它取得初始化權並建立叢集,再依序啟動 pg02、pg03,以 Replica 身分加入。最後只在目前 Primary 還原測試資料,確認資料能透過 PostgreSQL 原生串流複寫抵達兩台 Replica。

完整的安裝、設定檔、TLS 憑證路徑、systemd 服務單元、啟動順序與資料還原命令放在文件庫:

GitHub 實作文件:Day 23|PostgreSQL HA 叢集實作(上):使用 Patroni 完成自動選主與狀態管理

本次實作摘要

  1. 確認既有邏輯備份可讀,停用原本由套件管理的 PostgreSQL 服務,並保存舊資料目錄。
  2. 在 pg01、pg02、pg03 安裝 Patroni,準備各節點可讀取的 etcd 用戶端憑證。
  3. 建立三份 Patroni 設定。scopenamespace、DCS 端點與 Bootstrap 內容相同,namelistenconnect_address 各自唯一。
  4. 驗證三份設定並建立 systemd 服務單元,先保持 Patroni 尚未啟動。
  5. 先啟動 pg01 並確認完成 Bootstrap,再依序啟動 pg02、pg03,等待複本建立完成。
  6. 檢查 DCS 動態設定、pg_hba 規則解析結果與 pg_rewind 前置條件。
  7. 使用主機防火牆限制 PostgreSQL 5432 與 Patroni 8008 的來源,完成允許與阻擋測試。
  8. 只在目前 Primary 還原既有邏輯備份,再從 Primary 與兩台 Replica 檢查角色、複寫與資料。
  9. 比較 /primary/replica/health 的 HTTP 結果,確認 REST API 表達的角色與 PostgreSQL 實際狀態一致。

驗證一:本次 Patroni 設定具有共同叢集與唯一節點身分

三台設定使用相同的 scope: iron-pgnamespace: /service/ 與三個 etcd 端點,但 name、REST API 位址與 PostgreSQL 位址分別對應 pg01、pg02、pg03。三份設定都必須先通過 patroni --validate-config,並由 postgres 帳號讀取 etcd 用戶端私鑰。

pg01 的 Patroni 設定通過驗證並使用預期的節點位址與 etcd 端點

圖(六)pg01 的 Patroni 設定通過驗證,節點名稱、REST API、PostgreSQL、資料目錄與三個 etcd 端點均符合本次規劃,postgres 也能讀取 etcd 用戶端私鑰。

驗證二:PostgreSQL 生命週期由 Patroni 統一管理

本次建立新的 /var/lib/postgresql/18/patroni 資料目錄,原本的資料目錄則保存為 main.day22。套件預設的 postgresql.service 停用後,由 patroni.service 維持開機啟動。執行中的 PostgreSQL 程序應由 Patroni 啟動並指向新的資料目錄。

pg01 停用套件預設 PostgreSQL 服務並由 Patroni 管理新的資料目錄

圖(七)pg01 已停用套件預設的 PostgreSQL 服務,Patroni 則保持啟用及執行,實際資料目錄為 /var/lib/postgresql/18/patroni

驗證三:三個成員形成單一 Primary 與兩個 Replica

patronictl list 應同時列出 pg01、pg02、pg03,而且只有一個成員顯示 Leader,其餘兩個顯示 Replica。再從 PostgreSQL 查詢 pg_is_in_recovery(),可確認 Patroni 顯示的角色和資料庫本身一致。兩項結果共同驗證 Patroni 已實際管理本次 PostgreSQL 叢集的角色。

本次由 pg01 完成首次建立,但 Leader 是由 Patroni 動態維持的角色,後續重新選主時可能改由 pg02 或 pg03 接手。本組驗證畫面拍攝時 pg03 是 Leader。判讀時應確認叢集維持一台 Leader 與兩台 Replica,擔任 Primary 的節點則可隨重新選主改變。

Patroni 叢集包含 pg03 Leader、pg01 與 pg02 Replica,pg01 處於復原狀態

圖(八)patronictl list 顯示 pg03 是 Leader,pg01、pg02 是 Replica。pg01 的 pg_is_in_recovery()true,與 Patroni 角色一致。

pg02 的 PostgreSQL 處於復原狀態並擔任 Replica

圖(九)pg02 的 pg_is_in_recovery()true,確認第二台複本的 PostgreSQL 實際角色。

pg03 的 pg_is_in_recovery() 回傳 false,並擔任 Primary

圖(十)pg03 的 pg_is_in_recovery()false,與 patronictl list 顯示的 Leader 角色一致。

驗證四:首次建立設定已成為 DCS 的動態設定

叢集建立後,patronictl show-config iron-pg 應顯示 ttl: 30loop_wait: 10retry_timeout: 10maximum_lag_on_failover: 1048576use_slots: trueuse_pg_rewind: true。HBA 檔案還要包含 rewind_user 使用的 hostssl 規則。pg_hba_file_rules 用來確認目前檔案內容與解析結果。實際 pg_rewind 可用性會在舊 Primary 回歸測試中驗證。

Patroni DCS 顯示本次使用的控制迴圈、領導者鎖定與複寫設定

圖(十一)DCS 動態設定保留本次使用的 loop_waitretry_timeoutttl、候選延遲門檻、複寫槽與 pg_rewind 設定。

PostgreSQL 已辨識 rewind_user 使用的 hostssl 與 SCRAM-SHA-256 規則

圖(十二)pg_hba_file_rules 顯示 rewind_userhostssl 規則限制來源為資料庫網段,驗證方式為 SCRAM-SHA-256,且規則沒有解析錯誤。

證明:REST API 會依目前角色回傳不同結果

對三台節點分別查詢 /primary/replica。目前 Primary 的 /primary 應回傳 200,兩台 Replica 的 /replica 應回傳 200。不符合角色的端點則回傳非 200。再查詢 /health,可以看出程序健康和資料庫角色是兩種不同條件。

三台 Patroni 的 primary、replica 與 health 端點依目前角色回傳不同 HTTP 狀態

圖(十三)pg03 的 /primary 回傳 HTTP 200,pg01、pg02 的 /replica 回傳 HTTP 200,三台 /health 皆回傳 HTTP 200。

驗證五:還原資料由 Primary 傳入串流複寫

既有邏輯備份只還原到目前 Primary。Primary 的 pg_stat_replication 應看到另外兩台 Replica 的兩條 streaming 連線,兩台 Replica 的 pg_is_in_recovery() 應為 true。本次再以 pg01 查詢 replication_demo,確認資料筆數、ID 範圍與最新內容和 Primary 一致。這些結果驗證資料由 PostgreSQL 原生 WAL 複寫傳送,Patroni 專注管理角色與生命週期。

目前 Primary pg03 維持 pg01 與 pg02 兩條串流複寫連線

圖(十四)目前 Primary pg03 看見 pg01、pg02 兩條 streaming 連線,本機 pg_is_in_recovery() 回傳 false,測試資料共有 38 筆。

Replica pg01 處於復原狀態並具有與 Primary 相同的資料範圍

圖(十五)Replica pg01 處於復原狀態,資料筆數與 ID 範圍均和 Primary 相同,也能讀取最新五筆資料。

Lab 證據對照

要回答的問題 證據 判讀方式
三台是否屬於同一 Patroni 叢集 scopenamespace、DCS 端點與 patroni --validate-config 共用叢集識別與 DCS,節點名稱及位址各自唯一
PostgreSQL 是否交由 Patroni 管理 systemd 狀態、資料目錄與 PostgreSQL 程序 Patroni 啟用,套件預設 PostgreSQL 服務停用,本次執行個體使用 Patroni 資料目錄
是否只有一台可寫節點 patronictl listpg_is_in_recovery() 一台 Leader/false,兩台 Replica/true
Bootstrap 設定是否已寫入 DCS patronictl show-config 顯示本次計時、複寫槽與 pg_rewind 設定
pg_rewind 驗證規則是否能正確解析 pg_hba_file_rules rewind_userhostssl 規則存在且沒有解析錯誤
REST API 是否正確表達角色 三台 /primary/replica/health HTTP 200 出現在符合相應角色與健康條件的節點
PostgreSQL 與 Patroni 連接埠是否只接受規劃來源 nftables 規則與正反連線測試 pg 節點可以互連,ca01 無法直接連線 5432/8008
資料是否由 PostgreSQL 複寫 pg_stat_replication、復原狀態與 pg01 資料查詢 Primary 看見兩條串流連線,pg01 的資料與 Primary 一致

正式環境注意事項

  • 密碼、etcd 用戶端私鑰與管理用 REST 認證資料應由祕密管理系統或受限設定檔提供,不得寫入公開儲存庫。
  • TCP 8008 同時具有健康查詢與管理能力,應限制來源並依風險啟用 TLS 與驗證。一般應用程式只需要資料庫服務入口。
  • 修改動態設定前要保存目前值並檢查是否產生 pending restart。需要重啟時一次處理一個 Replica,確認叢集健康後再繼續。
  • Patroni 負責資料庫角色與生命週期管理。固定連線入口、連線池、獨立備份與完整監控則由其他元件提供。

今天完成了什麼

  • 分清 PostgreSQL 資料路徑與 Patroni、etcd 控制路徑。
  • 理解本機、動態與首次建立設定的作用範圍。
  • 由第一台 Patroni 完成一次 Bootstrap,再讓兩台 Replica 加入既有叢集。
  • 讓 Patroni 成為本次 PostgreSQL 執行個體的生命週期管理者。
  • 使用主機防火牆限制 PostgreSQL 與 Patroni 服務的連線來源。
  • 理解 HA Loop 如何讀取 DCS 與本機狀態並維持領導者鎖定。
  • 使用 patronictl、PostgreSQL 查詢與 REST API 交叉確認單一 Primary、兩台 Replica 及串流複寫。

下一篇預告

下一篇是 Day 24|PostgreSQL HA 叢集實作(下):計畫性切換、故障切換與舊 Primary 安全回歸。我們會在今天建立的 Patroni 三節點叢集上執行計畫性切換與故障切換,觀察領導鎖、資料庫角色與 PostgreSQL 時間軸如何改變,並確認新 Primary 可以接受寫入、舊 Primary 能安全回到 Replica 角色。


參考資料


上一篇
Day 22|Patroni 如何讓 PostgreSQL 叢集取得一致決策?三節點 etcd、Raft 與 mTLS
下一篇
Day 24|PostgreSQL HA 叢集實作(下):計畫性切換、故障切換與舊 Primary 安全回歸
系列文
從裸機到叢集:以 Proxmox VE、Ceph、OPNsense 與 PostgreSQL HA 建立可驗證的安全私有雲24
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言